/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.ua.miect.sd.simuladorpesca.threads;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import pt.ua.miect.sd.simuladorpesca.entities.Company;
import org.apache.log4j.Logger;
import pt.ua.miect.sd.simuladorpesca.SimulationConfig;
import pt.ua.miect.sd.simuladorpesca.entities.Boat;
import pt.ua.miect.sd.simuladorpesca.entities.FleetMessageBox;
import pt.ua.miect.sd.simuladorpesca.entities.RadioMessage;
import pt.ua.miect.sd.simuladorpesca.entities.SimulatorSeasons;

/**
 *
 * @author PedroA
 */
public class CompanyOperationsWorker implements Runnable, ISimWorker {

    private CyclicBarrier tickBarrier;
    private Company company;
    private Thread t;

    public CompanyOperationsWorker(String companyID, CyclicBarrier tick, int boats) {
        this.tickBarrier = tick;
        company = new Company(companyID, boats);
        t = new Thread(this);
        //Simulator.registerWorker(this);
    }

    public void start() {
        t.start();

    }

    @Override
    public void run() {
        Logger.getRootLogger().info(company.getCompanyID() + " has opened for business!");
        int activeBoats = getCompany().getBoats().size();
        boolean done = false;
        SimulatorSeasons currentSeason = SimulatorSeasons.Spowning_Season;
        int seasonCountDown = SimulationConfig.SPROWNING_SEASON_LENGHT;
        long seasonCatch = 0; //sum of all the catch
        FleetMessageBox fmb = FleetMessageBox.getInstance();
        while (!done) {
            try {
                tickBarrier.await();
                boolean hasMessages = true;
                do {
                    RadioMessage msg = FleetMessageBox.getInstance().getRadioMessage(company.getCompanyID());
                    if (msg == null) {
                        hasMessages = false;
                    } else {
                        switch (msg.getMessage()) {
                            case FoundFish:
                                List<Boat> boats = company.getBoats();
                                ArrayList<Boat> availableBoats = new ArrayList<Boat>();
                                for (Boat boat : boats) {
                                    if (boat.getId().equals(msg.getSenderID())) {
                                        continue;
                                    }
                                    if (boat.getStatus() == Boat.BoatStatus.SearchingForFish) {
                                        availableBoats.add(boat);
                                    }
                                }
                                if (availableBoats.size() > 0) {
                                    int minDistance = SimulationConfig.MAX_X_POSITION * SimulationConfig.MAX_Y_POSITION;
                                    Boat toBeSent = null;
                                    for (Boat boat : availableBoats) {
                                        int distance = boat.getMapPosition().getDistance(msg.getPosition());
                                        if (minDistance > distance) {
                                            minDistance = distance;
                                            toBeSent = boat;
                                        }
                                    }
                                    if (toBeSent != null) {
                                         FleetMessageBox.getInstance().setRadioMessage(
                                                new RadioMessage(msg.getSenderID(), toBeSent.getId(), RadioMessage.MessageType.JoinCatch,msg.getPosition()));
                                    } else {
                                        //these case should not be possible
                                        FleetMessageBox.getInstance().setRadioMessage(
                                                new RadioMessage(company.getCompanyID(), msg.getSenderID(), RadioMessage.MessageType.Abort));
                                    }
                                } else {
                                    //there is no other boats to help, catch will be aborted
                                    FleetMessageBox.getInstance().setRadioMessage(
                                            new RadioMessage(company.getCompanyID(), msg.getSenderID(), RadioMessage.MessageType.Abort));
                                }
                                break;
                            case AtHome:
                                int boatsAtPort = 0;
                                for (Boat boat : company.getBoats()) {
                                    if (boat.getId().equals(msg.getSenderID()))
                                    {
                                        seasonCatch += boat.getFishcount();
                                    }
                                    if (boat.getStatus() == Boat.BoatStatus.AtPort)
                                    {
                                        boatsAtPort++;
                                    }
                                }
                                if (company.getBoats().size() == boatsAtPort)
                                {
                                    Logger.getRootLogger().info(company.getCompanyID()+ " Reported that they managed to catch "+ seasonCatch+ " fish this season!");
                                }
                                break;

                        }
                    }
                } while (hasMessages);

                seasonCountDown--;
                if (seasonCountDown == 0) {
                    switch (currentSeason) {
                        case Spowning_Season:
                            //moving to next season
                            currentSeason = SimulatorSeasons.Fishing_Season;
                            seasonCountDown = SimulationConfig.FISHING_SEASON_LENGHT;
                            seasonCatch = 0;
                            int count = 0;
                            for (Boat boat : company.getBoats()) {
                                RadioMessage msg = new RadioMessage(company.getCompanyID(), boat.getId(), RadioMessage.MessageType.SeasonStart);
                                fmb.setRadioMessage(msg);
                                count ++;
                                if (count == activeBoats)
                                {
                                    break;
                                }
                            }
                            break;
                        case Fishing_Season:
                            currentSeason = SimulatorSeasons.Spowning_Season;
                            seasonCountDown = SimulationConfig.SPROWNING_SEASON_LENGHT;
                            for (Boat boat : company.getBoats()) {
                                RadioMessage msg = new RadioMessage(company.getCompanyID(), boat.getId(), RadioMessage.MessageType.EndOfSeason);
                                fmb.setRadioMessage(msg);
                            }
                    }
                }


            } catch (InterruptedException ex) {
                Logger.getLogger(CompanyOperationsWorker.class).error(ex);
                done = true;
            } catch (BrokenBarrierException ex) {
                Logger.getLogger(CompanyOperationsWorker.class).error(ex);
                done = true;
            }
        }

    }

    /**
     * @return the company
     */
    public Company getCompany() {
        return company;

    }
}
